package autoz.czt.wizards.pages;

import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.wizard.IWizardPage;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;

import autoz.core.wizards.NewProjectModel;

public class MainPage extends WizardPage{

	// references to required objects
	NewProjectModel model;
	
	// widgets on this page 
	Button createModelDirectory;
	Button createOutputDirectory;
	Button addTemplateDirectory;
	Combo latexTemplates;
	Text outputFile;
	Text modelDirectory;
	Text projectName;
	Text outputDirectory;
	
	// status variable for the possible errors on this page
	IStatus modelDirectoryStatus;
	IStatus outputDirectoryStatus;
	IStatus outputFileStatus;
	IStatus projectNameStatus;
		

	/**
	 * Constructor for MainPage.
	 */
	public MainPage(NewProjectModel model) {
		super("Page1");
		setTitle("New AUtoCADiZ project");
		setDescription("Specify the settings of your project");
		
		this.model = model;
		
		modelDirectoryStatus = new Status(IStatus.OK, "not_used", 0, "", null); //TODO maybe set these to be in error straight away?
		projectNameStatus = new Status(IStatus.OK, "not_used", 0, "", null);
	}

	/**
	 * Adds the components to the dialog.
	 */
	public void createControl(Composite parent) {

	    // create the composite to hold the widgets
		GridData gd;
		Composite composite =  new Composite(parent, SWT.NULL);

	    // create the desired layout for this wizard page
		GridLayout gl = new GridLayout();
		int ncol = 1;
		gl.numColumns = ncol;
		composite.setLayout(gl);		
		
// Project information
		
		Group projectInfoGroup = new Group(composite, SWT.SHADOW_ETCHED_IN);
		projectInfoGroup.setLayout(new GridLayout(2, false));
		projectInfoGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
		projectInfoGroup.setText("Project information: ");
		
		
		new Label (projectInfoGroup, SWT.None).setText("Project name:");
		projectName = new Text(projectInfoGroup, SWT.BORDER);
		gd = new GridData(GridData.FILL_HORIZONTAL);
//		gd.horizontalSpan = ncol - 1;
		projectName.setLayoutData(gd);	
		projectName.addModifyListener(new ModifyListener(){

			public void modifyText(ModifyEvent e) {
					switch (projectNameIsValid(projectName.getText())){
						case INVALIDCHAR:
							projectNameStatus = new Status(IStatus.ERROR, "not_used", 0, 
									"Invalid character in the project name field.", null);
							break;
						case NAMEEXISTS:
							projectNameStatus = new Status(IStatus.ERROR, "not_used", 0, 
									"Project name already exists.  Please choose another.", null);
							break;
						case VALID:
							model.setProjectName(projectName.getText());
							projectNameStatus = new Status(IStatus.OK, "not_used", 0, "", null);
							break;
						case ISBLANK:
							projectNameStatus = new Status(IStatus.ERROR, "not_used", 0, 
									"Project name cannot be empty.", null);
							break;
					}

					applyToStatusLine(findMostSevere());
			}
			
		});
		
// Model directory
		
		Group modelDirGroup = new Group(composite, SWT.SHADOW_ETCHED_IN);
		modelDirGroup.setLayout(new GridLayout(2, false));
		modelDirGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
		modelDirGroup.setText("Model directory: ");
		
		createModelDirectory = new Button(modelDirGroup, SWT.CHECK);
		createModelDirectory.setText("Create directory for models");
		createModelDirectory.setSelection(true);
		gd = new GridData(GridData.FILL_HORIZONTAL);
		gd.horizontalSpan = 2;
		createModelDirectory.setLayoutData(gd);
		createModelDirectory.addSelectionListener(new SelectionListener(){

			public void widgetDefaultSelected(SelectionEvent e) {
				// TODO Auto-generated method stub
				
		    	if (createModelDirectory.getSelection()){
		    		modelDirectory.setEnabled(true);
		    		modelDirectory.setFocus();
	    		}
		    	else {
		    		modelDirectory.setEnabled(false);	 
		    		model.setCreateModelDirectory(false);
		    	}
			}

			public void widgetSelected(SelectionEvent e) {
				// TODO Auto-generated method stub
		    	if (createModelDirectory.getSelection()){
		    		modelDirectory.setEnabled(true);
		    		modelDirectory.setFocus();
	    		}
		    	else {
		    		modelDirectory.setEnabled(false);	 
		    		model.setCreateModelDirectory(false);   		
		    	}
			}
			
		});
		
		new Label (modelDirGroup, SWT.None).setText("Models directory:");
		modelDirectory = new Text(modelDirGroup, SWT.BORDER);
		modelDirectory.setText("Models");
		model.setCreateModelDirectory(true);				// Need to set the default to create the folder
		model.setModelDirectory(modelDirectory.getText());
		
		gd = new GridData(GridData.FILL_HORIZONTAL);
		modelDirectory.setLayoutData(gd);
		modelDirectory.addModifyListener(new ModifyListener(){

			public void modifyText(ModifyEvent e) {
					switch (projectNameIsValid(modelDirectory.getText())){
						case INVALIDCHAR:
							modelDirectoryStatus = new Status(IStatus.ERROR, "not_used", 0, 
									"Invalid character in the model directory field.", null);
							break;
						case NAMEEXISTS:
							// Do nothing - it's not a project
							break;
						case VALID:
							model.setCreateModelDirectory(true);
							model.setModelDirectory(modelDirectory.getText());
							modelDirectoryStatus = new Status(IStatus.OK, "not_used", 0, "", null);
							break;
						case ISBLANK:
							modelDirectoryStatus = new Status(IStatus.ERROR, "not_used", 0, 
								"Model directory cannot be empty.", null); 
							break;
					}
					applyToStatusLine(findMostSevere());
			}
			
		});
		
// Output directory
		
		Group outputDirGroup = new Group(composite, SWT.SHADOW_ETCHED_IN);
		outputDirGroup.setLayout(new GridLayout(2, false));
		outputDirGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
		outputDirGroup.setText("Output directory: ");
		
		createOutputDirectory = new Button(outputDirGroup, SWT.CHECK);
		createOutputDirectory.setText("Create directory for Z output");
		createOutputDirectory.setSelection(true);
		gd = new GridData(GridData.FILL_HORIZONTAL);
		gd.horizontalSpan = 2;
		createOutputDirectory.setLayoutData(gd);
		createOutputDirectory.addSelectionListener(new SelectionListener(){

			public void widgetDefaultSelected(SelectionEvent e) {
				// TODO Auto-generated method stub
				
		    	if (createOutputDirectory.getSelection()){
		    		outputDirectory.setEnabled(true);
		    		outputDirectory.setFocus();
	    		}
		    	else {
		    		outputDirectory.setEnabled(false);	 
		    		model.setCreateOutputDirectory(false);
		    	}
			}

			public void widgetSelected(SelectionEvent e) {
				// TODO Auto-generated method stub
		    	if (createOutputDirectory.getSelection()){
		    		outputDirectory.setEnabled(true);
		    		outputDirectory.setFocus();
	    		}
		    	else {
		    		outputDirectory.setEnabled(false);	 
		    		model.setCreateOutputDirectory(false);   		
		    	}
			}
			
		});
		
		new Label (outputDirGroup, SWT.None).setText("Output directory:");
		outputDirectory = new Text(outputDirGroup, SWT.BORDER);
		outputDirectory.setText("Output");
		model.setCreateOutputDirectory(true);				// Need to set the default to create the folder
		model.setOutputDirectory(outputDirectory.getText());
		
		gd = new GridData(GridData.FILL_HORIZONTAL);
		outputDirectory.setLayoutData(gd);
		outputDirectory.addModifyListener(new ModifyListener(){

			public void modifyText(ModifyEvent e) {
					switch (projectNameIsValid(outputDirectory.getText())){
						case INVALIDCHAR:
							outputDirectoryStatus = new Status(IStatus.ERROR, "not_used", 0, 
									"Invalid character in the output directory field.", null);
							break;
						case NAMEEXISTS:
							// Do nothing - it's not a project
							break;
						case VALID:
							model.setCreateOutputDirectory(true);
							model.setOutputDirectory(outputDirectory.getText());
							outputDirectoryStatus = new Status(IStatus.OK, "not_used", 0, "", null);
							break;
						case ISBLANK:
							outputDirectoryStatus = new Status(IStatus.ERROR, "not_used", 0, 
								"Output directory cannot be empty.", null); 
							break;
					}
					applyToStatusLine(findMostSevere());
			}
			
		});
	    	   
		
// Output files
		Group outputFilesGroup = new Group(composite, SWT.SHADOW_ETCHED_IN);
		outputFilesGroup.setLayout(new GridLayout(2, false));
		outputFilesGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
		outputFilesGroup.setText("Output files: ");
		
		new Label (outputFilesGroup, SWT.None).setText("Z output file:");
		outputFile = new Text(outputFilesGroup, SWT.BORDER);
		outputFile.setText("Output.tex");
		model.setOutputFileName(outputFile.getText());
		
		gd = new GridData(GridData.FILL_HORIZONTAL);
		outputFile.setLayoutData(gd);
		outputFile.addModifyListener(new ModifyListener(){

			public void modifyText(ModifyEvent e) {
					switch (projectNameIsValid(outputFile.getText())){
						case INVALIDCHAR:
							outputFileStatus = new Status(IStatus.ERROR, "not_used", 0, 
									"Invalid character in the output file field.", null);
							break;
						case NAMEEXISTS:
							// Do nothing - it's not a project
							break;
						case VALID:
							model.setOutputFileName(outputFile.getText());
							outputFileStatus = new Status(IStatus.OK, "not_used", 0, "", null);
							break;
						case ISBLANK:
							outputFileStatus = new Status(IStatus.ERROR, "not_used", 0, 
								"Output file cannot be empty.", null); 
							break;
					}
					applyToStatusLine(findMostSevere());
			}
			
		});
			
		new Label (outputFilesGroup, SWT.None).setText("LaTeX template:");
		latexTemplates = new Combo(outputFilesGroup, SWT.DROP_DOWN);
		latexTemplates.add("report");
		latexTemplates.add("scrreprt");
		latexTemplates.select(0);
		model.setLatexTemplate(NewProjectModel.LatexTemplateType.REPORT);
		latexTemplates.addSelectionListener(new SelectionListener(){

			public void widgetDefaultSelected(SelectionEvent e) {
				String sel = latexTemplates.getText().trim();
				if (sel == "report")
					model.setLatexTemplate(NewProjectModel.LatexTemplateType.REPORT);
				else if (sel == "scrreprt")
					model.setLatexTemplate(NewProjectModel.LatexTemplateType.SCRREPRT);
			}

			public void widgetSelected(SelectionEvent e) {
				String sel = latexTemplates.getText().trim();
				if (sel.equals("report"))
					model.setLatexTemplate(NewProjectModel.LatexTemplateType.REPORT);
				else if (sel.equals("scrreprt"))
					model.setLatexTemplate(NewProjectModel.LatexTemplateType.SCRREPRT);				
			}
			
		});
// Expert options
		
		createLine(composite, ncol);	
		
		// Give the option to use custom templates
		addTemplateDirectory = new Button(composite, SWT.CHECK);
		addTemplateDirectory.setText("Add UML+Z templates to project for customisation (Expert users only)");
		addTemplateDirectory.setSelection(false);
		gd = new GridData(GridData.FILL_HORIZONTAL);
		gd.horizontalSpan = ncol;
		addTemplateDirectory.setLayoutData(gd);
		addTemplateDirectory.addSelectionListener(new SelectionListener(){

			public void widgetDefaultSelected(SelectionEvent e) {
				// TODO Auto-generated method stub
				
		    	if (addTemplateDirectory.getSelection()){
		    		model.setAddTemplateDirectory(true);
	    		}
		    	else {
		    		model.setAddTemplateDirectory(false);
		    	}
			}

			public void widgetSelected(SelectionEvent e) {
				// TODO Auto-generated method stub
		    	if (addTemplateDirectory.getSelection()){
		    		model.setAddTemplateDirectory(true);
	    		}
		    	else {
		    		model.setAddTemplateDirectory(false);   		
		    	}
			}
			
		});
		
	    // set the composite as the control for this page
		setControl(composite);		
	}

	/**
	 * @see IWizardPage#canFlipToNextPage()
	 */
	public boolean canFlipToNextPage()
	{
		return false;
	}
	
	private enum ProjectNameValidity {VALID, INVALIDCHAR, NAMEEXISTS, ISBLANK};
	
    /**
     * Check that the project name has no illegal characters and that there isn't already
     * and existing project with the same name.
     * @param text
     * @return
     */
    private ProjectNameValidity projectNameIsValid(String text) {

    	IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
		IProject project = root.getProject(text);
		
		if (text.trim().length() == 0)
			return ProjectNameValidity.ISBLANK;
		else if (text.indexOf('/') >= 0 || text.indexOf('\\') >= 0)
        	return ProjectNameValidity.INVALIDCHAR;
        else if (project.exists())
        	return ProjectNameValidity.NAMEEXISTS;
    	else 
        	return ProjectNameValidity.VALID;
        
    }

	/**
	 * Applies the status to the status line of a dialog page.
	 */
	private void applyToStatusLine(IStatus status) {
		String message= status.getMessage();
		if (message.length() == 0) message= null;
		switch (status.getSeverity()) {
			case IStatus.OK:
				setErrorMessage(null);
				setMessage(message);
				break;
			case IStatus.WARNING:
				setErrorMessage(null);
				setMessage(message, WizardPage.WARNING);
				break;				
			case IStatus.INFO:
				setErrorMessage(null);
				setMessage(message, WizardPage.INFORMATION);
				break;			
			default:
				setErrorMessage(message);
				setMessage(null);
				break;		
		}
	}	
	
	/**
	 * Finds the most severe status message to display.
	 * @return Most severe status
	 */
	private IStatus findMostSevere()
	{
		if (projectNameStatus.matches(IStatus.ERROR))
			return projectNameStatus;
		if (modelDirectoryStatus.matches(IStatus.ERROR))
			return modelDirectoryStatus;
		else 
			return new Status(IStatus.OK, "not_used", 0, "", null);	
	}

	/**
	 * Draws a separator.
	 * @param parent
	 * @param ncol
	 */
	private void createLine(Composite parent, int ncol) 
	{
		Label line = new Label(parent, SWT.SEPARATOR|SWT.HORIZONTAL|SWT.BOLD);
		GridData gridData = new GridData(GridData.FILL_HORIZONTAL);
		gridData.horizontalSpan = ncol;
		line.setLayoutData(gridData);
	}

}
